use ggez::{glam::Vec2,Context, graphics, mint::Point2};
use rand::Rng;

use crate::animation::Animation;
use crate::mover::Mover;
use crate::physics::Physics;
use crate::visual::Visual;
use crate::animover::Animover;

pub struct Balloon {
    physics : Physics,
    visual: Visual,
    tail: Vec<Point2<f32>>
}

impl Balloon {
    pub fn new(location: Vec2) -> Balloon {
        let mut rng = rand::thread_rng();
        let velocity = Vec2{x: 0.0, y: 0.0};
        let acceleration = Vec2 { x: 0.0, y: 0.0 };
        let factor = rng.gen_range(10.0..30.0);
        let topspeed = 70.0;
        let mass = factor*factor*factor*0.001;
        let physics = Physics{location, velocity, topspeed, acceleration, mass};
        let color = graphics::Color::new(0.0, 0.0, 0.0, 0.8);
        let size = factor;
        let visual = Visual{color, size};
        let tail = vec![];
        Balloon {physics, visual, tail}
    }

    pub fn limit(&mut self) -> () {
        if self.physics.velocity.length() > self.physics.topspeed {self.physics.velocity = self.physics.topspeed*self.physics.velocity.normalize()}
    }

}

impl Mover for Balloon {
    fn apply_force(&mut self, force: Vec2) -> () {
        if !force.is_nan() {self.physics.acceleration += force};
    }

    fn get_location(& self) -> Vec2 {
        self.physics.location
    }

    fn get_mass(& self) -> f32 {
        self.physics.mass
    }
    
    fn get_velocity(& self) -> Vec2 {
        self.physics.velocity
    }
}

impl Animation for Balloon {
    fn update(&mut self, ctx: &mut Context) -> () {
        self.physics.acceleration /= self.physics.mass;
        self.physics.velocity += self.physics.acceleration;
        self.limit();
        
        self.physics.location += self.physics.velocity;
        self.physics.acceleration *= 0.0;
        // self.physics.check_edges(ctx);

        self.tail.push(Point2{x: self.get_location().x, y: self.get_location().y});
    }

    fn display(&self, ctx: &mut Context, canvas : &mut graphics::Canvas) -> () {
        let polyline = graphics::Mesh::new_polyline(
            ctx, 
            graphics::DrawMode::stroke(1.0), 
            self.tail.as_slice(), 
            graphics::Color::new(0.3, 0.0, 0.4, 0.2)
        ).unwrap();
        canvas.draw(&polyline, graphics::DrawParam::default());

        let circle = graphics::Mesh::new_circle(
            ctx,
            graphics::DrawMode::fill(),
            Point2{x: self.physics.location.x, y: self.physics.location.y},
            self.visual.size,
            0.1,
            self.visual.color,
        ).unwrap();
        canvas.draw(&circle, graphics::DrawParam::default());
        let circle = graphics::Mesh::new_circle(
            ctx,
            graphics::DrawMode::stroke(2.0),
            Point2{x: self.physics.location.x, y: self.physics.location.y},
            self.visual.size,
            0.1,
            graphics::Color::BLACK,
        ).unwrap();
        canvas.draw(&circle, graphics::DrawParam::default());
    }
}

impl Animover for Balloon {}